#include <stdio.h>
#include <SDL2/SDL.h>

//event message
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
#define QUIT_EVENT  (SDL_USEREVENT + 2)

int thread_exit = 0;

int refresh_video_timer(void *udata) {

  thread_exit = 0;

  while (!thread_exit) {
    SDL_Event event;
    event.type = REFRESH_EVENT;
    SDL_PushEvent(&event);
    SDL_Delay(40);
  }

  thread_exit = 0;

  //push quit event
  SDL_Event event;
  event.type = QUIT_EVENT;
  SDL_PushEvent(&event);

  return 0;
}

int main(int argc, char *argv[]) {

  FILE *video_fd = NULL;

  SDL_Event event;
  SDL_Rect rect;

  Uint32 pix_format = 0;

  SDL_Window *win = NULL;
  SDL_Renderer *renderer = NULL;
  SDL_Texture *texture = NULL;

  SDL_Thread *timer_thread = NULL;

  int w_width = 640;
  int w_height = 480;
  //yuv需要指定视频的width和height
  const int video_width = 1920, video_height = 1080;

  Uint8 *video_pos = NULL;
  Uint8 *video_buf = NULL;
  unsigned int video_buff_len = 0;

  const char *path = "/Users/admin/Downloads/out.yuv";

  const unsigned int yuv_frame_len = video_width * video_height * 12 / 8;
  unsigned int tmp_yuv_frame_len = yuv_frame_len;
  if (yuv_frame_len & 0xF) {
    tmp_yuv_frame_len = (yuv_frame_len & 0xFFF0) + 0x10;
  }

  //initialize SDL
  if (SDL_Init(SDL_INIT_VIDEO)) {
    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    return -1;
  }

  //creat window from SDL
  win = SDL_CreateWindow("YUV Player",
                         SDL_WINDOWPOS_UNDEFINED,
                         SDL_WINDOWPOS_UNDEFINED,
                         w_width, w_height,
                         SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
  if (!win) {
    fprintf(stderr, "Failed to create window, %s\n", SDL_GetError());
    goto __FAIL;
  }

  renderer = SDL_CreateRenderer(win, -1, 0);

  //IYUV: Y + U + V  (3 planes)
  //YV12: Y + V + U  (3 planes)
  pix_format = SDL_PIXELFORMAT_IYUV;

  //create texture for render
  texture = SDL_CreateTexture(renderer,
                              pix_format,
                              SDL_TEXTUREACCESS_STREAMING,
                              video_width,
                              video_height);
  video_buf = (Uint8 *) malloc(tmp_yuv_frame_len);
  if (!video_buf) {
    fprintf(stderr, "Failed to alloc yuv frame space\n");
    goto __FAIL;
  }

  //open yuv file
  video_fd = fopen(path, "r");
  if (!video_fd) {
    fprintf(stderr, "Failed to open yuv file\n");
    goto __FAIL;
  }

  //read block data
  if (video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd) <= 0) {
    fprintf(stderr, "Failed to read data from yuv file!\n");
    goto __FAIL;
  }

  //set video positon
  video_pos = video_buf;

  timer_thread = SDL_CreateThread(refresh_video_timer,
                                  NULL,
                                  NULL);
  do {
    //Wait
    SDL_WaitEvent(&event);
    if (event.type == REFRESH_EVENT) {

      SDL_UpdateTexture(texture, NULL, video_pos, video_width);

      //FIX: If window is resize
      rect.x = 0;
      rect.y = 0;
      rect.w = w_width;
      rect.h = w_height;

      SDL_RenderCopy(renderer, texture, NULL, &rect);
      SDL_RenderPresent(renderer);
      if ((video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd)) <= 0) {
        thread_exit = 1;
        continue;
      }

    } else if (event.type == SDL_WINDOWEVENT) {
      //If Resize
      SDL_GetWindowSize(win, &w_width, &w_height);
    } else if (event.type == SDL_QUIT) {
      thread_exit = 1;
    } else if (event.type == QUIT_EVENT) {
      break;
    }
  } while (1);

  __FAIL:
  if (video_buf) {
    free(video_buf);
  }
  //close file
  if (video_fd) {
    fclose(video_fd);
  }

  SDL_Quit();
  return 0;
}

